package com.spddr.pmos.cxf.tree.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.spddr.pmos.cxf.tree.CheckedTreeNode;
import com.spddr.pmos.cxf.tree.JaxrsLevel;
import com.spddr.pmos.domain.TreeLevel;
import com.spddr.pmos.repos.CompanyRepos;
import com.spddr.pmos.repos.CustomerRepos;
import com.spddr.pmos.repos.GridRepos;
import com.spddr.pmos.repos.LineRepos;
import com.spddr.pmos.repos.PlantRepos;
import com.spddr.pmos.repos.ReservoirRepos;
import com.spddr.pmos.repos.RiverRepos;
import com.spddr.pmos.repos.SubstationRepos;
import com.spddr.pmos.repos.TelemetryStationRepos;
import com.spddr.pmos.repos.TransformerRepos;
import com.spddr.pmos.repos.TransmissionRepos;
import com.spddr.pmos.repos.UnitRepos;
import com.spddr.pmos.repos.UsagePointRepos;

import cn.seqdata.jpa.JpaAuditableObject;
import cn.seqdata.pojo.TreeNode;

public abstract class AbstractTreeImpl implements JaxrsLevel<TreeNode> {
	@Autowired
	protected GridRepos gridRepos;
	@Autowired
	protected CompanyRepos companyRepos;
	@Autowired
	protected CustomerRepos customerRepos;
	@Autowired
	protected PlantRepos plantRepos;
	@Autowired
	protected UnitRepos unitRepos;
	@Autowired
	protected SubstationRepos substationRepos;
	@Autowired
	protected TransformerRepos transformerRepos;
	@Autowired
	protected LineRepos lineRepos;
	@Autowired
	protected TransmissionRepos transmissionRepos;
	@Autowired
	protected RiverRepos riverRepos;
	@Autowired
	protected ReservoirRepos reservoirRepos;
	@Autowired
	protected UsagePointRepos usagepointRepos;
	@Autowired
	protected TelemetryStationRepos telemetryRepos;

	@Override
	public Collection<TreeNode> byLevel(long id, TreeLevel level) {
		if (0L == id)
			return byRoot();

		switch (level) {
		case Grid:
			return byGrid(id);
		case Company:
			return byCompany(id);
		case Customer:
			return byCustomer(id);
		case Plant:
			return byPlant(id);
		case Unit:
			return byUnit(id);
		case Substation:
			return bySubstation(id);
		case Transformer:
			return byTransformer(id);
		case Line:
			return byLine(id);
		case Transmission:
			return byTransmission(id);
		case River:
			return byRiver(id);
		case Reservoir:
			return byReservoir(id);
		case UsageGroup:
		case UsagePoint:
			return byUsagePoint(id);
		case Telemetry:
		case Hydrology:
		case Weather:
		case Rain:
			return byTelemetry(id);
		default:
			return Collections.emptyList();
		}
	}

	@Override
	public Collection<TreeNode> byGrid(long grid) {
		return byJpaObject(true, transmissionRepos.findByFromGridIdOrToGridId(grid, grid));
	}

	@Override
	public Collection<TreeNode> byCompany(long company) {
		List<TreeNode> nodes = new ArrayList<>();
		nodes.addAll(byJpaObject(true, companyRepos.findByParentId(company)));
		nodes.addAll(byJpaObject(true, plantRepos.findByCompanyId(company)));
		return nodes;
	}

	@Override
	public Collection<TreeNode> byCustomer(long customer) {
		return Collections.emptyList();
	}

	@Override
	public Collection<TreeNode> byPlant(long plant) {
		List<TreeNode> nodes = new ArrayList<>();
		nodes.addAll(byJpaObject(false, unitRepos.findByPlantId(plant)));
		nodes.addAll(byJpaObject(true, substationRepos.findByPlantId(plant)));
		return nodes;
	}

	@Override
	public Collection<TreeNode> byUnit(long unit) {
		return Collections.emptyList();
	}

	@Override
	public Collection<TreeNode> bySubstation(long substation) {
		List<TreeNode> nodes = new ArrayList<>();
		nodes.addAll(byJpaObject(false, lineRepos.findBySubstationId(substation)));
		nodes.addAll(byJpaObject(false, transformerRepos.findBySubstationId(substation)));
		return nodes;
	}

	@Override
	public Collection<TreeNode> byTransformer(long transformer) {
		return Collections.emptyList();
	}

	@Override
	public Collection<TreeNode> byLine(long line) {
		return Collections.emptyList();
	}

	@Override
	public Collection<TreeNode> byTransmission(long transmission) {
		return Collections.emptyList();
	}

	@Override
	public Collection<TreeNode> byRiver(long river) {
		List<TreeNode> nodes = new ArrayList<>();
		nodes.addAll(byJpaObject(true, riverRepos.findBySpillsIntoId(river)));
		nodes.addAll(byJpaObject(true, reservoirRepos.findByRiverId(river)));
		return nodes;
	}

	@Override
	public Collection<TreeNode> byReservoir(long reservoir) {
		List<TreeNode> nodes = new ArrayList<>();
		nodes.addAll(byJpaObject(true, plantRepos.findByReservoirId(reservoir)));
		return nodes;
	}

	@Override
	public Collection<TreeNode> byUsagePoint(long usagepoint) {
		return Collections.emptyList();
	}

	@Override
	public Collection<TreeNode> byTelemetry(long telemetry) {
		return Collections.emptyList();
	}

	protected Collection<TreeNode> byJpaObject(final boolean isContainer,
			Collection<? extends JpaAuditableObject> objects) {
		return Collections2.transform(objects, new Function<JpaAuditableObject, TreeNode>() {
			@Override
			public TreeNode apply(JpaAuditableObject input) {
				return new CheckedTreeNode(input, isContainer);
			}
		});
	}

	protected Collection<TreeNode> byJpaObject(final boolean isContainer, final TreeLevel level,
			Collection<? extends JpaAuditableObject> objects) {
		return Collections2.transform(objects, new Function<JpaAuditableObject, TreeNode>() {
			@Override
			public TreeNode apply(JpaAuditableObject input) {
				CheckedTreeNode node = new CheckedTreeNode(input, isContainer);
				node.setLevel(level);
				return node;
			}
		});
	}
}
